package com.gitee.l0km.jsonvisitor.utils;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.antlr.v4.runtime.CharStreams.fromChannel;
import static org.antlr.v4.runtime.CharStreams.fromPath;
import static org.antlr.v4.runtime.CharStreams.fromReader;
import static org.antlr.v4.runtime.CharStreams.fromStream;
import static org.antlr.v4.runtime.CharStreams.fromString;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URI;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.IntBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Path;

import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CodePointBuffer;
import org.antlr.v4.runtime.CodePointCharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.TokenStream;

import com.gitee.l0km.jsonvisitor.listener.ParserErrorListener;
import com.google.common.base.Throwables;

public class CharStreamSupport {

	/**
	 * 创建ANTLR4词法分析器对象
	 * @param <L> 泛型参数：词法分析器类型
	 * @param input 待解析的字符流对象
	 * @param lexerType 词法分析器类型
	 */
	public static <L extends Lexer> L lexerOf(CharStream input,Class<L> lexerType) {
		try {
			return checkNotNull(lexerType,"lexerType is null").getConstructor(CharStream.class).newInstance(checkNotNull(input,"input is null"));
		} catch (Exception e) {
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}
	}

	/**
	 * 创建ANTLR4词法分析器对象
	 * @param <L> 泛型参数：词法分析器类型
	 * @param input 待解析的数据对象
	 * @param lexerType 词法分析器类型
	 */
	public static <L extends Lexer> L lexerOf(Object input,Class<L> lexerType) {
		return lexerOf(CharStreamSupport.asCharStream(input), lexerType);
	}

	/**
	 * 创建ANTLR4生成的语法分析器对象
	 * @param parserType 语法分析器类型
	 * @param input 待解析的字符流对象
	 * @param <L> 泛型参数：词法分析器类型
	 * @param <P> 泛型参数：语法分析器类型
	 */
	public static <L extends Lexer,P extends Parser > P parserOf(L lexer,Class<P> parserType) {
		try {
			CommonTokenStream tokens = new CommonTokenStream(lexer);
			P parser =  checkNotNull(parserType,"parserType is null").getConstructor(TokenStream.class).newInstance(tokens);
			parser.removeErrorListeners();
			parser.addErrorListener(ParserErrorListener.INSTANCE);
			return parser;
		} catch (Exception e) {
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}
	}

	/**
	 * 创建ANTLR4生成的语法分析器对象
	 * @param <L> 泛型参数：词法分析器类型
	 * @param <P> 泛型参数：语法分析器类型
	 * @param input 待解析的字符流对象
	 * @param lexerType 词法分析器类型
	 * @param parserType 语法分析器类型
	 */
	public static <L extends Lexer,P extends Parser > P parserOf(CharStream input,Class<L> lexerType,Class<P> parserType) {
		return parserOf(lexerOf(input,lexerType),parserType);
	}
	/**
	 * 创建ANTLR4生成的语法分析器对象
	 * @param <L> 泛型参数：词法分析器类型
	 * @param <P> 泛型参数：语法分析器类型
	 * @param input 待解析的数据对象
	 * @param lexerType 词法分析器类型
	 * @param parserType 语法分析器类型
	 */
	public static <L extends Lexer,P extends Parser > P parserOf(Object input,Class<L> lexerType,Class<P> parserType) {
		return parserOf(CharStreamSupport.asCharStream(input), lexerType, parserType);
	}

	/**
	 * 将数据源转为{@link CharStream}<br>
	 * 支持的类型：<br>
	 * {@link CharStream},{@link Path},{@link File},{@link InputStream},{@link ReadableByteChannel},
	 * {@link URL},{@link URI}, {@link Reader},{@link String},{@link ByteBuffer},{@link CharBuffer},{@link IntBuffer},
	 * byte[],char[],int[]<br>
	 * 否则抛出异常{@link IllegalArgumentException}
	 * @param src
	 * @throws IllegalArgumentException 不支持的数据源类型
	 */
	public static CharStream asCharStream(Object src) throws IllegalArgumentException {
		try {			
			if(src instanceof CharStream) {
				return (CharStream)src;
			}else if(src instanceof Path) {
				return fromPath((Path)src);
			}else if(src instanceof File) {
				return asCharStream(((File)src).toPath());
			}else if(src instanceof InputStream) {
				return fromStream((InputStream)src);
			}else if(src instanceof ReadableByteChannel) {
				return fromChannel((ReadableByteChannel)src);
			}else if(src instanceof URL) {
				return asCharStream(((URL)src).openStream());
			}else if(src instanceof URI) {
				return asCharStream(((URI)src).toURL());
			}else if(src instanceof Reader) {
				return fromReader((Reader)src);
			}else if(src instanceof String) {
				return fromString((String)src);
			}else if(src instanceof ByteBuffer) {
				CodePointBuffer buffer = CodePointBuffer.withBytes((ByteBuffer)src);
				return CodePointCharStream.fromBuffer(buffer);
			}else if(src instanceof CharBuffer) {
				CodePointBuffer buffer = CodePointBuffer.withChars((CharBuffer)src);
				return CodePointCharStream.fromBuffer(buffer);
			}else if(src instanceof IntBuffer) {
				CodePointBuffer buffer = CodePointBuffer.withInts((IntBuffer)src);
				return CodePointCharStream.fromBuffer(buffer);
			}else if(src instanceof byte[]) {
				return asCharStream(ByteBuffer.wrap((byte[])src));
			}else if(src instanceof char[]) {
				return asCharStream(CharBuffer.wrap((char[])src));
			}else if(src instanceof int[]) {
				return asCharStream(IntBuffer.wrap((int[])src));
			}else if(null != src) {
				throw new IllegalArgumentException("UNSUPPORTED Source Type:"+src.getClass().getName());
			}
			return null;
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

}
